#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include"heap_timer.h"
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include "locker.h"
#include "threadpool.h"
#include "http_conn.h"
#define TIMESLOT 10
#define MAX_FD 65536   // 最大的文件描述符个数
#define MAX_EVENT_NUMBER 10000  // 监听的最大的事件数量
static time_heap heap(MAX_FD);
// 添加文件描述符
extern void addfd( int epollfd, int fd, bool one_shot );
extern void removefd( int epollfd, int fd );
void cb_func(client_data* user_data){
    user_data->info.close_conn();
    close(user_data->info.m_sockfd);
}
int main( int argc, char* argv[] ) {

    if( argc <= 1 ) {
        printf( "usage: %s port_number\n", basename(argv[0]));
        return 1;
    }

    int port = atoi( argv[1] );

    threadpool< http_conn >* pool = NULL;
    try {
        pool = new threadpool<http_conn>;
    } catch( ... ) {
        return 1;
    }

    client_data* users = new client_data[ MAX_FD ];
    int listenfd = socket( PF_INET, SOCK_STREAM, 0 );

    int ret = 0;
    struct sockaddr_in address;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_family = AF_INET;
    address.sin_port = htons( port );
    // 端口复用
    int reuse = 1;
    setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ) );
    ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) );
    ret = listen( listenfd, 5 );

    // 创建epoll对象，和事件数组，添加
    epoll_event events[ MAX_EVENT_NUMBER ];
    int epollfd = epoll_create( 5 );
    // 添加到epoll对象中
    addfd( epollfd, listenfd, false );
    http_conn::m_epollfd = epollfd;
    int timeout=-1;
    while(true) {
        int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, (timeout-time(NULL))*1000);
        if ( ( number < 0 ) && ( errno != EINTR ) ) {
            printf( "epoll failure\n" );
            break;
        }
        for ( int i = 0; i < number; i++ ) {

            int sockfd = events[i].data.fd;

            if( sockfd == listenfd ) {

                struct sockaddr_in client_address;
                socklen_t client_addrlength = sizeof( client_address );
                int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength );

                if ( connfd < 0 ) {
                    printf( "errno is: %d\n", errno );
                    continue;
                }

                if( http_conn::m_user_count >= MAX_FD ) {
                    close(connfd);
                    continue;
                }
                users[connfd].info.init( connfd, client_address);
                heap_timer* timer=new heap_timer;
                timer->expire=time(NULL)+TIMESLOT;
                timer->cb_func=cb_func;
                timer->user_data=&users[connfd];
                users[connfd].timer=timer;
                heap.add_timer(timer);

            }else if( events[i].events & ( EPOLLRDHUP | EPOLLHUP | EPOLLERR ) ) {

                users[sockfd].info.close_conn();

            } else if(events[i].events & EPOLLIN) {

                if(users[sockfd].info.read()) {
                    pool->append(&users[sockfd].info);
                    users[sockfd].timer->expire=time(NULL)+TIMESLOT;
                } else {
                    users[sockfd].info.close_conn();
                }

            }  else if( events[i].events & EPOLLOUT ) {

                if( !users[sockfd].info.write() ) {
                    users[sockfd].info.close_conn();
                }
            }
        }
        heap.tick();
        if(!heap.empty()) timeout=heap.top()->expire;
        else timeout=-1;
    }

    close( epollfd );
    close( listenfd );
    delete [] users;
    delete pool;
    return 0;
}